/*
 * Copyright ThinkTank Maths Limited 2007
 *
 * This file is free software: you can redistribute it and/or modify it under the terms of
 * the GNU Lesser General Public License as published by the Free Software Foundation, either
 * version 3 of the License, or (at your option) any later version.
 *
 * This file is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
 * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
 * PURPOSE. See the GNU Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public License along with this file.
 * If not, see <http://www.gnu.org/licenses/>.
 */
package suit.image;

import java.io.ByteArrayOutputStream;
import java.io.DataOutputStream;
import java.io.IOException;

public class BMP extends Image {

	private int size;
	private int pad;
	private int w;
	private int h;
	private int[] rgb;

	private ImageListener listener;
	public void connect(ImageListener listener) {
		this.listener = listener;
	}

	public BMP(javax.microedition.lcdui.Image image) {
		super(image);
		w = image.getWidth();
		h = image.getHeight();
		rgb = new int[h * w];

		image.getRGB(rgb, 0, w, 0, 0, w, h);

		pad = (4 - (w % 4)) % 4;
		size = 14 + 40 + h * (pad + w * 3);
	}

	public void encode(DataOutputStream stream) throws IOException {
		//listener.onStart();
		stream.writeByte(0x42);
		stream.writeByte(0x4D);
		stream.writeInt(swapEndian(size));
		stream.writeInt(0);
		stream.writeInt(swapEndian(54));
		stream.writeInt(swapEndian(40));
		stream.writeInt(swapEndian(w));
		stream.writeInt(swapEndian(h));
		stream.writeShort(swapEndian((short) 1));
		stream.writeShort(swapEndian((short) 24));
		stream.writeInt(0);
		stream.writeInt(0);
		stream.writeInt(0);
		stream.writeInt(0);
		stream.writeInt(0);
		stream.writeInt(0);
		int val, j, i;
		for (j = h - 1; j >= 0; j--) {
			//listener.onProgress((double) 1 - ((double) j / (double) h-1));
			for (i = 0; i < w; i++) {
				val = rgb[i + w * j];
				stream.writeByte(val & 0x000000FF);
				stream.writeByte((val >>> 8) & 0x000000FF);
				stream.writeByte((val >>> 16) & 0x000000FF);
			}
			for (i = 0; i < pad; i++) {
				stream.writeByte(0);
			}
		}
		listener.onComplete();
	}

	public byte[] encode() {

		try {
			ByteArrayOutputStream bytes = new ByteArrayOutputStream(size);
			DataOutputStream stream = new DataOutputStream(bytes);
			encode(stream);
			byte[] out = bytes.toByteArray();
			bytes.close();
			return out;
		} catch (IOException e) {
			return null;
		}
	}

	/**
	 * Swap the Endian-ness of a 32 bit integer.
	 * 
	 * @param value
	 * @return
	 */
	private static int swapEndian(int value) {
		int b1 = value & 0xff;
		int b2 = (value >> 8) & 0xff;
		int b3 = (value >> 16) & 0xff;
		int b4 = (value >> 24) & 0xff;

		return b1 << 24 | b2 << 16 | b3 << 8 | b4 << 0;
	}

	/**
	 * Swap the Endian-ness of a 16 bit integer.
	 * 
	 * @param value
	 * @return
	 */
	private static short swapEndian(short value) {
		int b1 = value & 0xff;
		int b2 = (value >> 8) & 0xff;

		return (short) (b1 << 8 | b2 << 0);
	}

}
